import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 有 n 个城市通过一些航班连接。给你一个数组flights ，其中flights[i] = [fromi, toi, pricei] ，表示该航班都从城市 fromi 开始，以价格 pricei 抵达 toi。
 *
 * 现在给定所有的城市和航班，以及出发城市 src 和目的地 dst，你的任务是找到出一条最多经过 k站中转的路线，使得从 src 到 dst 的 价格最便宜 ，并返回该价格。 如果不存在这样的路线，则输出 -1。
 *
 * 示例 1：
 * 输入: 
 * n = 3, edges = [[0,1,100],[1,2,100],[0,2,500]]
 * src = 0, dst = 2, k = 1
 * 输出: 200
 * 解释: 
 * 城市航班图如下
 * 从城市 0 到城市 2 在 1 站中转以内的最便宜价格是 200，如图中红色所示。
 *
 * 示例 2：
 * 输入: 
 * n = 3, edges = [[0,1,100],[1,2,100],[0,2,500]]
 * src = 0, dst = 2, k = 0
 * 输出: 500
 * 解释: 
 * 城市航班图如下
 * 从城市 0 到城市 2 在 0 站中转以内的最便宜价格是 500，如图中蓝色所示。
 *
 * 提示：
 * 1 <= n <= 100
 * 0 <= flights.length <= (n * (n - 1) / 2)
 * flights[i].length == 3
 * 0 <= fromi, toi < n
 * fromi != toi
 * 1 <= pricei <= 104
 * 航班没有重复，且不存在自环
 * 0 <= src, dst, k < n
 * src != dst
 *
 * 来源：力扣（LeetCode）
 * 链接：https://leetcode-cn.com/problems/cheapest-flights-within-k-stops
 * 著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。
 */

/**
 * 动态规划好像才能解
 */
public class Q00787m_Todo {

    private int ans;

    private List<int[]>[] outgoings;

    private int[] prices;

    private boolean[] visited;

    public int findCheapestPrice(int n, int[][] flights, int src, int dst, int k) {
        ans = Integer.MAX_VALUE;
        outgoings = new List[n];
        prices = new int[n];
        Arrays.fill(prices, Integer.MAX_VALUE);
        visited = new boolean[n];
        for (int[] flight : flights) {
            if (outgoings[flight[0]] == null) {
                outgoings[flight[0]] = new ArrayList<>();
            }
            outgoings[flight[0]].add(new int[]{flight[1], flight[2]});
        }
        backtrace(src, dst, k, 0);
        return ans == Integer.MAX_VALUE ? -1 : ans;
    }

    private void backtrace(int src, int dst, int k, int price) {
        if (visited[src] || outgoings[src] == null) return;
        if (prices[src] != Integer.MAX_VALUE) {
            if (prices[src] <= price) {
                return;
            }
            ans = ans - (prices[src] - price);
            return;
        }

        visited[src] = true;
        if (k == 0) {
            for (int[] outAndPrice : outgoings[src]) {
                if (outAndPrice[0] == dst) {
                    ans = Math.min(price + outAndPrice[1], ans);
                    for (int i = 0; i < visited.length; i++) {
                        if (!visited[i]) {
                            prices[i] = Integer.MAX_VALUE;
                        }
                    }
                    break;
                }
            }
        } else {
            k--;
            for (int[] outAndPrice : outgoings[src]) {
                if (outAndPrice[0] == dst) {
                    ans = Math.min(price + outAndPrice[1], ans);
                    for (int i = 0; i < visited.length; i++) {
                        if (!visited[i]) {
                            prices[i] = Integer.MAX_VALUE;
                        }
                    }
                } else {
                    backtrace(outAndPrice[0], dst, k, price + outAndPrice[1]);
                }
            }
        }
        visited[src] = false;
    }

}
